using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace PacketScreensaver.Net.PacketMonitor
{
    #region Enumerations
    public enum Precedence
    {
        Routine = 0,
        Priority = 1,
        Immediate = 2,
        Flash = 3,
        Flash_Override = 4,
        Critic_Ecp = 5,
        Internetwork_Control = 6,
        Network_Control = 7
    }

    public enum Delay
    {
        Normal = 0,
        Low = 1
    }

    public enum Throughput
    {
        Normal = 0,
        High = 1
    }

    public enum Reliability
    {
        Normal = 0,
        High = 1
    }

    public enum Protocol
    {
        Ggp = 3,
        Icmp = 1,
        Idp = 22,
        Igmp = 2,
        Ip = 4,
        Nd = 77,
        Pup = 12,
        Tcp = 6,
        Udp = 17,
        Other = -1
    }
    #endregion

    public class Packet
    {
        #region Private Fields
        private int _version;
        private int _headerLength;
        private Precedence _precedence;
        private Delay _delay;
        private Throughput _throughput;
        private Reliability _reliability;
        private int _totalLength;
        private int _identification;
        private bool _mayFragment;
        private bool _lastFragment;
        private int _timeToLive;
        private Protocol _protocol;
        private int _headerChecksum;
        private IPAddress _sourceAddress;
        private IPAddress _destinationAddress; 
        #endregion

        #region Properties
        public int Version
        {
            get { return _version; }
        }

        public int HeaderLength
        {
            get { return _headerLength; }
        }

        public Precedence Precedence
        {
            get { return _precedence; }
        }

        public Delay Delay
        {
            get { return _delay; }
        }

        public Throughput Throughput
        {
            get { return _throughput; }
        }

        public Reliability Reliability
        {
            get { return _reliability; }
        }

        public int TotalLength
        {
            get { return _totalLength; }
        }

        public int Identification
        {
            get { return _identification; }
        }

        public bool MayFragment
        {
            get { return _mayFragment; }
        }

        public bool LastFragment
        {
            get { return _lastFragment; }
        }

        public int TimeToLive
        {
            get { return _timeToLive; }
        }

        public Protocol Protocol
        {
            get { return _protocol; }
        }

        public int HeaderChecksum
        {
            get { return _headerChecksum; }
        }

        public IPAddress SourceAddress
        {
            get { return _sourceAddress; }
        }

        public IPAddress DestinationAddress
        {
            get { return _destinationAddress; }
        } 
        #endregion

        #region Constructor
        /// <summary>
        /// Instantiates the Packet class.  
        /// </summary>
        /// <param name="data">The raw bytes of an IP packet.</param>
        public Packet(byte[] data)
        {
            if (data.Length <= 20)
                throw new InvalidPacketException();

            _version = data[0] & 0xf0 >> 4;
            _headerLength = data[0] & 0x0f;
            _precedence = (Precedence)(data[1] & 0xe0 >> 5);
            _delay = (Delay)(data[1] & 0x10 >> 4);
            _throughput = (Throughput)(data[1] & 0x08 >> 3);
            _reliability = (Reliability)(data[1] & 0x04 >> 2);
            _totalLength = (data[2] << 8) + data[3];
            _identification = (data[4] << 8) + data[5];
            _mayFragment = Convert.ToBoolean(data[6] & 0x40);
            _lastFragment = Convert.ToBoolean(data[7] & 0x20);
            _timeToLive = data[8];
            _protocol = (Protocol)data[9];
            _headerChecksum = (data[10] << 8) + data[11];
            _sourceAddress = new IPAddress(BitConverter.ToUInt32(data, 12));
            _destinationAddress = new IPAddress(BitConverter.ToUInt32(data, 16));
        } 
        #endregion
    }

    #region Exceptions
    [global::System.Serializable]
    public class InvalidPacketException : Exception
    {
        //
        // For guidelines regarding the creation of new exception types, see
        //    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp
        // and
        //    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp
        //

        public InvalidPacketException() { }
        public InvalidPacketException(string message) : base(message) { }
        public InvalidPacketException(string message, Exception inner) : base(message, inner) { }
        protected InvalidPacketException(
          System.Runtime.Serialization.SerializationInfo info,
          System.Runtime.Serialization.StreamingContext context)
            : base(info, context) { }
    } 
    #endregion
}
